package br.ufpr.inf.escel.brain.model;

import br.ufpr.inf.escel.brain.impl.IndividualImpl;
import br.ufpr.inf.escel.brain.util.NumeroUtils;
import br.ufpr.inf.escel.brain.variator.Variator;
import br.ufpr.inf.escel.consts.Constantes;
import br.ufpr.inf.escel.testing.Console;
import br.ufpr.inf.escel.testing.model.Cut;
import br.ufpr.inf.escel.testing.model.CutPO;
import br.ufpr.inf.escel.testing.model.CutPP;
import br.ufpr.inf.escel.testing.tools.impl.Ferramenta;
import java.io.File;
import java.util.LinkedList;

/** Specifies the problem-specific behavior of an individual.
 * Defines the decision space representation of the individuals,
 * provides two constructors
 * and implements methods to calculate the objective space values of an individual
 * and to create a copy of an individual.
 * 
 * @author Tamara Ulrich
 * @version 1.0
 */
public class Individual implements IndividualImpl {

    private Integer id;
    private double[] objectiveSpace;
    private LinkedList<DadoTeste> dadosTeste;
    private Cut cut;
    private Ferramenta jabuti;
    private Ferramenta proteum;
    private Ferramenta poketool;

    /** Standard class constructor, initializes the decision space representation randomly. */
    public Individual() {
        this.dadosTeste = new LinkedList<DadoTeste>();
        this.objectiveSpace = new double[2];
    }

    private Individual(Integer id, double[] objectiveSpace,
            LinkedList<DadoTeste> dadosTeste,
            Cut cut,
            Ferramenta poke,
            Ferramenta proteum,
            Ferramenta jabuti) {

        this.id = id;
        this.objectiveSpace = objectiveSpace;
        this.dadosTeste = dadosTeste;
        this.cut = cut;
        this.poketool = poke;
        this.proteum = proteum;
        this.jabuti = jabuti;
    }

    public void add(DadoTeste dt) {
        this.dadosTeste.add(dt);
    }

    public void moverArquivos() {
        String[] mover = {
            "cd " + cut.getNovoPath(),
            "mv TestCase* completo.xml *.trc " + ((CutPO) cut).projectName() + " ind" + id
        };

        Console.getInstance().run(mover);
    }

    public void update(DadoTeste antigo, DadoTeste novo) {
        for (int i = 0; i < objectiveSpace.length; i++) {
            if (antigo.equals(dadosTeste.get(i))) {
                dadosTeste.set(i, novo);
            }
        }
    }

    public void initTools(Cut cut) {
        if (cut instanceof CutPP) {
            poketool = Ferramenta.getTool("POKE");
            proteum = Ferramenta.getTool("PROTEUM");
            poketool.setCut(cut);
            proteum.setCut(cut);
        } else {
            jabuti = Ferramenta.getTool("JABUTI");
            jabuti.setCut(cut);
        }
        this.cut = cut;
    }

    public DadoTeste getDadoTeste(int index) {
        return dadosTeste.get(index);
    }

    public void eval() {
        
        if (Constantes.TIPO_PROGRAMA.equals("PO")) {
            criarPasta();
            this.objectiveSpace[0] = jabuti.run(this);
            this.objectiveSpace[1] = getObjectiveSpace()[1];
        } else if (Constantes.TIPO_PROGRAMA.equals("PP")) {
            this.objectiveSpace[0] = poketool.run(this);
            this.objectiveSpace[1] = proteum.run(this);

//            this.objectiveSpace[0] = Variator.randomGenerator.nextDouble() * 100;
//            this.objectiveSpace[1] = Variator.randomGenerator.nextDouble() * 100;
        } 
    }

    public Individual copy() {

        Ferramenta jabota = Ferramenta.getTool("JABUTI");
        if (Constantes.TIPO_PROGRAMA.equals("PO")) {
            jabota.setCut(cut);
        }

        Individual newInd = new Individual(
                this.id,
                this.objectiveSpace,
                this.dadosTeste,
                this.cut,
                this.poketool,
                this.proteum,
                jabota);
        return newInd;
    }

    private void criarPasta() {
        File pastaInd = new File(cut.getNovoPath() + "ind" + id);
        if (!pastaInd.exists()) {
            pastaInd.mkdir();
        }
    }

    public int getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getCapacidade() {
        return Constantes.NR_DADO_TESTES;
    }

    public double[] getObjectiveSpace() {
        return objectiveSpace;
    }

    public void setObjectiveSpace(double[] objectiveSpace) {
        this.objectiveSpace = objectiveSpace;
    }
    
    public LinkedList<DadoTeste> getDadosTeste() {
        return dadosTeste;
    }

    public String getScore() {
        StringBuffer saida = new StringBuffer("[");

        saida.append(NumeroUtils.toDecimal(objectiveSpace[0]));
        saida.append(" : ");
        saida.append(NumeroUtils.toDecimal(objectiveSpace[1]));
        saida.append("] ");

        return saida.toString();
    }

    @Override
    public boolean equals(Object object) {
        if (object == null || !this.getClass().equals(object.getClass())) {
            return false;
        }
        Individual other = (Individual) object;
        if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (this.id != null ? this.id.hashCode() : 0);
        return hash;
    }
}
